package xnum

import "math"

const (
	x_pi = math.Pi * 3000.0 / 180.0 // 圆周率对应的经纬度偏移
	a    = 6378245.0                // 长半轴
	ee   = 0.00669342162296594323   // 扁率
)

// 获取火星坐标
func (c *GPS) Gcj02() *GPS {
	switch c.types {
	case 0:
		return c.wgs84gcj02()
	case 1:
		return c
	case 2:
		return c.bd09gcj02()
	}
	return c
}

// 获取百度坐标
func (c *GPS) Bd09() *GPS {
	switch c.types {
	case 0:
		return c.wgs84gcj02().gcj02Bd09()
	case 1:
		return c.gcj02Bd09()
	case 2:
		return c
	}
	return c
}

// 获取GPS坐标
func (c *GPS) Gps() *GPS {
	switch c.types {
	case 0:
		return c
	case 1:
		return c.gcj02WGS84()
	case 2:
		return c.bd09gcj02().gcj02WGS84()
	}
	return c
}

// GPS坐标转火星坐标
func (receiver *GPS) wgs84gcj02() *GPS {
	if receiver.outOfChina() {
		return receiver
	}
	dLat := receiver.transformLat(receiver.Longitude-105.0, receiver.Latitude-35.0)
	dlng := receiver.transformlng(receiver.Longitude-105.0, receiver.Latitude-35.0)
	radLat := receiver.Latitude / 180.0 * math.Pi
	magic := math.Sin(radLat)
	magic = 1 - ee*magic*magic
	SqrtMagic := math.Sqrt(magic)
	dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * SqrtMagic) * math.Pi)
	dlng = (dlng * 180.0) / (a / SqrtMagic * math.Cos(radLat) * math.Pi)
	mgLat := receiver.Latitude + dLat
	mglng := receiver.Longitude + dlng
	return &GPS{
		Latitude:  mgLat,
		Longitude: mglng,
		types:     1,
	}
}

// 火星坐标转GPS坐标
func (receiver *GPS) gcj02WGS84() *GPS {
	receiver.transform()
	receiver.Latitude = receiver.Latitude*2 - receiver.Latitude
	receiver.Longitude = receiver.Longitude*2 - receiver.Longitude
	receiver.types = 0
	return receiver
}

// 火星坐标转百度坐标
func (receiver *GPS) gcj02Bd09() *GPS {
	z := math.Sqrt(receiver.Longitude*receiver.Longitude+receiver.Latitude*receiver.Latitude) + 0.00002*math.Sin(receiver.Latitude*x_pi)
	theta := math.Atan2(receiver.Latitude, receiver.Longitude) + 0.000003*math.Cos(receiver.Longitude*x_pi)
	templng := z*math.Cos(theta) + 0.0065
	tempLat := z*math.Sin(theta) + 0.006
	return &GPS{
		Latitude:  tempLat,
		Longitude: templng,
		types:     2,
	}
}

// 百度坐标转火星坐标
func (receiver *GPS) bd09gcj02() *GPS {
	x := receiver.Longitude - 0.0065
	y := receiver.Latitude - 0.006
	z := math.Sqrt(x*x+y*y) - 0.00002*math.Sin(y*x_pi)
	theta := math.Atan2(y, x) - 0.000003*math.Cos(x*x_pi)
	templng := z * math.Cos(theta)
	tempLat := z * math.Sin(theta)
	return &GPS{
		Latitude:  tempLat,
		Longitude: templng,
		types:     1,
	}
}

// 判断是否在国外
// 此坐标以GPS坐标计算，即使用时默认坐标已经是GPS坐标了
func (c *GPS) outOfChina() bool {
	if c.types > 0 {
		c = c.Gps()
	}
	if c.Latitude < 0.8293 || c.Latitude > 55.8271 {
		return true
	}
	if c.Longitude < 72.004 || c.Longitude > 137.8347 {
		return true
	}
	return false
}

func (receiver *GPS) transformLat(x, y float64) float64 {
	return -100.0 + 2.0*x + 3.0*y + 0.2*y*y + 0.1*x*y + 0.2*math.Sqrt(math.Abs(x)) +
		(20.0*math.Sin(6.0*x*math.Pi)+20.0*math.Sin(2.0*x*math.Pi))*2.0/3.0 +
		(20.0*math.Sin(y*math.Pi)+40.0*math.Sin(y/3.0*math.Pi))*2.0/3.0 +
		(160.0*math.Sin(y/12.0*math.Pi)+320*math.Sin(y*math.Pi/30.0))*2.0/3.0
}

func (receiver *GPS) transformlng(x, y float64) float64 {
	return 300.0 + x + 2.0*y + 0.1*x*x + 0.1*x*y + 0.1*math.Sqrt(math.Abs(x)) +
		(20.0*math.Sin(6.0*x*math.Pi)+20.0*math.Sin(2.0*x*math.Pi))*2.0/3.0 +
		(20.0*math.Sin(x*math.Pi)+40.0*math.Sin(x/3.0*math.Pi))*2.0/3.0 +
		(150.0*math.Sin(x/12.0*math.Pi)+300.0*math.Sin(x/30.0*math.Pi))*2.0/3.0
}

// 坐标转换
func (receiver *GPS) transform() *GPS {
	if receiver.outOfChina() {
		return receiver
	}
	dLat := receiver.transformLat(receiver.Longitude-105.0, receiver.Latitude-35.0)
	dlng := receiver.transformlng(receiver.Longitude-105.0, receiver.Latitude-35.0)
	radLat := receiver.Latitude / 180.0 * math.Pi
	magic := math.Sin(radLat)
	magic = 1 - ee*magic*magic
	SqrtMagic := math.Sqrt(magic)
	receiver.Longitude += (dlng * 180.0) / (a / SqrtMagic * math.Cos(radLat) * math.Pi)
	receiver.Latitude += (dLat * 180.0) / ((a * (1 - ee)) / (magic * SqrtMagic) * math.Pi)
	return receiver
}
